package com.tc.zookeeper.test;

import com.google.common.base.Objects;
import com.tc.property.PropertyManager;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * zk锁
 *
 * Author: liliangxing
 * Time: 2018-05-17.
 */
@Component
public class ZookeeperLock {

    @Value("${fcg.zookeeper.address}")
    private String zkServerUrl;

    @Value("${fcg.zookeeper.lockTime}")
    private long lockTime;

    private CuratorFramework client = null;

    private static final Logger log = LoggerFactory.getLogger(ZookeeperLock.class);

    @Autowired
    protected PropertyManager propertyManager;

    @PostConstruct
    public void init() {
        try {
            connect();
        } catch (Exception e) {
            log.error("zookeeper connect  error：" , e);
        }
    }

    /**
     * 初始化连接
     */
    private void connect() {
        client = CuratorFrameworkFactory.newClient(zkServerUrl, new ExponentialBackoffRetry(100, 3));
        client.start();
    }

    /**
     * 抢zk锁，重载方法，默认使用配置文件的锁定时间
     *
     */
    public InterProcessMutex acquire(String path) throws Exception {
        return acquire(path, lockTime);
    }

    /**
     * 抢zk锁，重载方法，可以自定义锁定时间
     * @param lockTime 锁定时间
     */
    public InterProcessMutex acquire(String path, long lockTime) throws Exception{
        InterProcessMutex lock = null;
        if (!"Y".equalsIgnoreCase(propertyManager.getProperty("fcgRefundDistributedLock")) || client == null){
            return null;
        }
        try {
            lock = new InterProcessMutex(client, path);
            if(!lock.acquire(lockTime, TimeUnit.SECONDS)){
                log.error("获取zk锁失败，路径{}",path);
                throw new Exception("获取zk锁失败");
            }
        } catch (Exception e) {
            throw new Exception("zk加锁错误");
        }
        return  lock;
    }

    /**
     * 释放zk锁
     * @param lock          InterProcessMutex
     * @param patch         锁定路径
     */
    public synchronized  void  release(InterProcessMutex lock, String patch) {
        try {
            if(lock != null){
                lock.release();
                // 尝试删除锁节点
                client.delete().forPath(patch);
            }
        }catch (KeeperException e) {
            //忽略zk锁子节点存在时删除节点失败
            if (!Objects.equal(e.code().name(), KeeperException.Code.NOTEMPTY.name())) {
                log.error("zookeeper lock KeeperException: {}",e);
            }
        } catch (Exception e) {
            log.error("zookeeper lock release fail:{}",e);
        }

    }
}
